home *** CD-ROM | disk | FTP | other *** search
/ Just Call Me Internet / Just Call Me Internet.iso / prog / atari / c / nos042_s / kernel.c < prev    next >
C/C++ Source or Header  |  1994-09-16  |  13KB  |  556 lines

  1. /* Non pre-empting synchronization kernel, machine-independent portion
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  */
  4.  
  5. /****************************************************************************
  6. *    $Id: kernel.c 1.4 93/07/16 11:45:57 ROOT_DOS Exp $
  7. *    13 Jul 93    1.3        GT    Fix warnings.                                    *
  8. *
  9. *    ATARI version by David Nash - dnash@chaos.demon.co.uk
  10. *
  11. ****************************************************************************/
  12.  
  13. #define    SUSPEND_PROC    1
  14.  
  15. #if    defined(PROCLOG) || defined(PROCTRACE)
  16. #include <stdio.h>
  17. #endif
  18. #include <dos.h>
  19. #include <setjmp.h>
  20. #include "global.h"
  21. #include "mbuf.h"
  22. #include "proc.h"
  23. #include "timer.h"
  24. #include "socket.h"
  25. #include "daemon.h"
  26. #include "hardware.h"
  27.  
  28. #ifdef    PROCLOG
  29. FILE *proclog;
  30. FILE *proctrace;
  31. #endif
  32. int Stkchk = 0;
  33. struct proc *Curproc;        /* Currently running process */
  34. struct proc *Rdytab;        /* Processes ready to run (not including curproc) */
  35. struct proc *Waittab[PHASH];    /* Waiting process list */
  36. struct proc *Susptab;        /* Suspended processes */
  37. static struct mbuf *Killq;
  38.  
  39. static void addproc __ARGS((struct proc *entry));
  40. static void delproc __ARGS((struct proc *entry));
  41.  
  42. #ifdef ATARI
  43. static unsigned phash __ARGS((void *event));
  44.        void init_psetup(struct proc *pp);
  45. #endif
  46.  
  47. /* Create a process descriptor for the main function. Must be actually
  48.  * called from the main function!
  49.  * Note that standard I/O is NOT set up here.
  50.  */
  51. struct proc *
  52. mainproc(name)
  53. char *name;
  54. {
  55.     register struct proc *pp;
  56.  
  57.     /* Create process descriptor */
  58.     pp = (struct proc *)callocw(1,sizeof(struct proc));
  59.  
  60.     /* Create name */
  61.     pp->name = strdup(name);
  62. #ifndef    AMIGA
  63. #ifndef  ATARI
  64.     pp->stksize = 0;
  65. #else
  66.     init_psetup(pp);
  67. #endif    
  68. #else
  69.     init_psetup(pp);
  70. #endif
  71.     /* Make current */
  72.     pp->state = READY;
  73.     Curproc = pp;
  74.  
  75. #ifdef    PROCLOG
  76.     proclog = fopen("proclog",APPEND_TEXT);
  77.     proctrace = fopen("proctrace",APPEND_TEXT);
  78. #endif
  79.     return pp;
  80. }
  81. /* Create a new, ready process and return pointer to descriptor.
  82.  * The general registers are not initialized, but optional args are pushed
  83.  * on the stack so they can be seen by a C function.
  84.  */
  85. struct proc *
  86. newproc(name,stksize,pc,iarg,parg1,parg2,freeargs)
  87. char *name;        /* Arbitrary user-assigned name string */
  88. unsigned int stksize;    /* Stack size in words to allocate */
  89. void (*pc)();        /* Initial execution address */
  90. int iarg;        /* Integer argument (argc) */
  91. void *parg1;        /* Generic pointer argument #1 (argv) */
  92. void *parg2;        /* Generic pointer argument #2 (session ptr) */
  93. int freeargs;        /* If set, free arg list on parg1 at termination */
  94. {
  95.     register struct proc *pp;
  96.     int i;
  97.  
  98.     if(Stkchk)
  99.         chkstk();
  100.  
  101.     /* Create process descriptor */
  102.     pp = (struct proc *)callocw(1,sizeof(struct proc));
  103.  
  104.     /* Create name */
  105.     pp->name = strdup(name);
  106.  
  107.     /* Allocate stack */
  108. #if defined(AMIGA) || defined(ATARI)
  109.     stksize += 2000;    /* DOS overhead */
  110. #endif
  111.     pp->stksize = stksize;
  112.     if((pp->stack = (int16 *)malloc(sizeof(int16)*stksize)) == NULL){
  113.         free(pp->name);
  114.         free((char *)pp);
  115.         return NULLPROC;
  116.     }
  117.     /* Initialize stack for high-water check */
  118.     for(i=0;i<stksize;i++)
  119.         pp->stack[i] = STACKPAT;
  120.  
  121.     /* Do machine-dependent initialization of stack */
  122.     psetup(pp,iarg,parg1,parg2,pc);
  123.  
  124.     pp->freeargs = freeargs;
  125.     pp->iarg = iarg;
  126.     pp->parg1 = parg1;
  127.     pp->parg2 = parg2;
  128.     
  129.     /* Inherit creator's input and output sockets */
  130.     usesock(Curproc->input);
  131.     pp->input = Curproc->input;
  132.     usesock(Curproc->output);
  133.     pp->output = Curproc->output;
  134.  
  135.     /* Add to ready process table */
  136.     pp->state = READY;
  137.     addproc(pp);
  138.     return pp;
  139. }
  140.  
  141. /* Free resources allocated to specified process. If a process wants to kill
  142.  * itself, the reaper is called to do the dirty work. This avoids some
  143.  * messy situations that would otherwise occur, like freeing your own stack.
  144.  */
  145. void
  146. killproc(pp)
  147. register struct proc *pp;
  148. {
  149.     char **argv;
  150.  
  151.     if(pp == NULLPROC)
  152.         return;
  153.     /* Don't check the stack here! Will cause infinite recursion if
  154.      * called from a stack error
  155.      */
  156.  
  157.     if(pp == Curproc)
  158.         killself();    /* Doesn't return */
  159.  
  160.     /* Close any open sockets */
  161.     freesock(pp);
  162.  
  163.     close_s(pp->input);
  164.     close_s(pp->output);
  165.  
  166.     /* Stop alarm clock in case it's running */
  167.     stop_timer(&pp->alarm);
  168.  
  169.     /* Alert everyone waiting for this proc to die */
  170.     psignal(pp,0);
  171.  
  172.     /* Remove from appropriate table */
  173.     delproc(pp);
  174.  
  175. #ifdef    PROCLOG
  176.     fprintf(proclog,"id %lx name %s stack %u/%u\n",ptol(pp),
  177.         pp->name,stkutil(pp),pp->stksize);
  178.     fclose(proclog);
  179.     proclog = fopen("proclog",APPEND_TEXT);
  180.     proctrace = fopen("proctrace",APPEND_TEXT);
  181. #endif
  182.     /* Free allocated memory resources */
  183.     if(pp->freeargs){
  184.         argv = pp->parg1;
  185.         while(pp->iarg-- != 0)
  186.             free(*argv++);
  187.         free(pp->parg1);
  188.     }
  189.     free(pp->name);
  190.     free(pp->stack);
  191.     free(pp->outbuf);
  192.     free((char *)pp);
  193. }
  194. /* Terminate current process by sending a request to the killer process.
  195.  * Automatically called when a process function returns. Does not return.
  196.  */
  197. void
  198. killself()
  199. {
  200.     register struct mbuf *bp;
  201.  
  202.     if(Curproc != NULLPROC){
  203.         bp = pushdown(NULLBUF,sizeof(Curproc));
  204.         memcpy(bp->data,(char *)&Curproc,sizeof(Curproc));
  205.         enqueue(&Killq,bp);
  206.     }
  207.     /* "Wait for me; I will be merciful and quick." */
  208.     for(;;)
  209.         pwait(NULL);
  210. }
  211. /* Process used by processes that want to kill themselves */
  212. void
  213. killer(i,v1,v2)
  214. int i;
  215. void *v1;
  216. void *v2;
  217. {
  218.     struct proc *pp;
  219.     struct mbuf *bp;
  220.  
  221.     for(;;){
  222.         while(Killq == NULLBUF)
  223.             pwait(&Killq);
  224.         bp = dequeue(&Killq);
  225.         pullup(&bp,(char *)&pp,sizeof(pp));
  226.         free_p(bp);
  227.         if(pp != Curproc)    /* We're immortal */
  228.             killproc(pp);
  229.     }                        
  230. }
  231.  
  232. #ifdef    SUSPEND_PROC
  233. /* Inhibit a process from running */
  234. void
  235. suspend(pp)
  236. struct proc *pp;
  237. {
  238.     if(pp == NULLPROC)
  239.         return;
  240.     if(pp != Curproc)
  241.         delproc(pp);    /* Running process isn't on any list */
  242.     pp->state |= SUSPEND;
  243.     if(pp != Curproc)
  244.         addproc(pp);    /* pwait will do it for us */
  245.     else
  246.         pwait(NULL);
  247. }
  248. /* Restart suspended process */
  249. void
  250. resume(pp)
  251. struct proc *pp;
  252. {
  253.     if(pp == NULLPROC)
  254.         return;
  255.     delproc(pp);    /* Can't be Curproc! */
  256.     pp->state &= ~SUSPEND;
  257.     addproc(pp);
  258. }
  259. #endif    /* SUSPEND_PROC */
  260.  
  261. /* Wakeup waiting process, regardless of event it's waiting for. The process
  262.  * will see a return value of "val" from its pwait() call.
  263.  */
  264. void
  265. alert(pp,val)
  266. struct proc *pp;
  267. int val;
  268. {
  269.     if(pp == NULLPROC)
  270.         return;
  271. #ifdef    notdef
  272.     if((pp->state & WAITING) == 0)
  273.         return;
  274. #endif
  275. #ifdef    PROCTRACE
  276.     printf("alert(%lx,%u) [%s]\n",ptol(pp),val,pp->name);
  277.     fflush(stdout);
  278. #endif
  279.     if(pp != Curproc)
  280.         delproc(pp);
  281.     pp->state &= ~WAITING;
  282.     pp->retval = val;
  283.     pp->event = 0;
  284.     if(pp != Curproc)
  285.         addproc(pp);
  286. }
  287.  
  288. /* Post a wait on a specified event and give up the CPU until it happens. The
  289.  * null event is special: it means "I don't want to block on an event, but let
  290.  * somebody else run for a while". It can also mean that the present process
  291.  * is terminating; in this case the wait never returns.
  292.  *
  293.  * Pwait() returns 0 if the event was signaled; otherwise it returns the
  294.  * arg in an alert() call. Pwait must not be called from interrupt level.
  295.  *
  296.  * Note that pwait can run with interrupts enabled even though it examines
  297.  * a few global variables that can be modified by psignal at interrupt time.
  298.  * These *seem* safe.
  299.  */
  300. int
  301. pwait(event)
  302. void *event;
  303. {
  304.     register struct proc *oldproc;
  305.     int tmp;
  306.  
  307.     if(Curproc != NULLPROC){    /* If process isn't terminating */
  308.         if(Stkchk)
  309.             chkstk();
  310.  
  311.         if(event == NULL){
  312.             /* Special case; just give up the processor.
  313.              *
  314.              * Optimization: if nothing else is ready, just return.
  315.              */
  316.             if(Rdytab == NULLPROC){
  317.                 return 0;
  318.             }
  319.         } else {
  320.             /* Post a wait for the specified event */
  321.             Curproc->event = event;
  322.             Curproc->state = WAITING;
  323.         }
  324.         addproc(Curproc);
  325.     }
  326.     /* Look for a ready process and run it. If there are none,
  327.      * loop or halt until an interrupt makes something ready.
  328.      */
  329.     while(Rdytab == NULLPROC){
  330.         /* Give system back to upper-level multitasker, if any.
  331.          * Note that this function enables interrupts internally
  332.          * to prevent deadlock, but it restores our state
  333.          * before returning.
  334.          */
  335. #ifndef ATARI         
  336.         kbint();    
  337.         giveup();
  338. #endif        
  339.     }
  340.     /* Remove first entry from ready list */
  341.     oldproc = Curproc;
  342.     Curproc = Rdytab;
  343.     delproc(Curproc);
  344.  
  345.     /* Now do the context switch.
  346.      * This technique was inspired by Rob, PE1CHL, and is a bit tricky.
  347.      *
  348.      * If the old process has gone away, simply load the new process's
  349.      * environment. Otherwise, save the current process's state. Then if
  350.      * this is still the old process, load the new environment. Since the
  351.      * new task will "think" it's returning from the setjmp() with a return
  352.      * value of 1, the comparison with 0 will bypass the longjmp(), which
  353.      * would otherwise cause an infinite loop.
  354.      */
  355. #ifdef    PROCTRACE
  356.     if(strcmp(oldproc->name,Curproc->name) != 0){
  357.           printf("-> %s(%d)\n",Curproc->name,!!Curproc->i_state);
  358.         fflush(stdout);
  359.     }
  360. #endif
  361.     /* Note use of comma operator to save old interrupt state only if
  362.      * oldproc is non-null
  363.      */
  364.     if(oldproc == NULLPROC
  365.      || (oldproc->i_state = istate(), setjmp(oldproc->env) == 0)){
  366.         /* We're still running in the old task; load new task context.
  367.          * The interrupt state is restored here in case longjmp
  368.          * doesn't do it (e.g., systems other than Turbo-C).
  369.          */
  370.         restore(Curproc->i_state);
  371.         longjmp(Curproc->env,1);
  372.     }
  373.     /* At this point, we're running in the newly dispatched task */
  374.     tmp = Curproc->retval;
  375.     Curproc->retval = 0;
  376.  
  377.     /* Also restore the true interrupt state here, in case the longjmp
  378.      * DOES restore the interrupt state saved at the time of the setjmp().
  379.      * This is the case with Turbo-C's setjmp/longjmp.
  380.      */
  381.     restore(Curproc->i_state);
  382.     return tmp;
  383. }
  384.  
  385. /* Make ready the first 'n' processes waiting for a given event. The ready
  386.  * processes will see a return value of 0 from pwait().  Note that they don't
  387.  * actually get control until we explicitly give up the CPU ourselves through
  388.  * a pwait(). Psignal may be called from interrupt level. It returns the
  389.  * number of processes that were woken up.
  390.  */
  391. int
  392. psignal(event,n)
  393. void *event;    /* Event to signal */
  394. int n;        /* Max number of processes to wake up */
  395. {
  396.     register struct proc *pp;
  397.     struct proc *pnext;
  398.     int i_state;
  399.     unsigned int hashval;
  400.     int cnt = 0;
  401.  
  402.     if(Stkchk)
  403.         chkstk();
  404.  
  405.     if(event == NULL)
  406.         return 0;        /* Null events are invalid */
  407.  
  408.     /* n = 0 means "signal everybody waiting for this event" */
  409.     if(n == 0)
  410.         n = (int) 65535L;
  411.  
  412.     hashval = phash(event);
  413.     i_state = dirps();
  414.     for(pp = Waittab[hashval];n != 0 && pp != NULLPROC;pp = pnext){
  415.         pnext = pp->next;
  416.         if(pp->event == event){
  417. #ifdef    PROCTRACE
  418.             if(i_state){
  419.                 printf("psignal(%lx,%u) wake %lx [%s]\n",ptol(event),n,
  420.                  ptol(pp),pp->name);
  421.                 fflush(stdout);
  422.             }
  423. #endif
  424.             delproc(pp);
  425.             pp->state &= ~WAITING;
  426.             pp->retval = 0;
  427.             pp->event = NULL;
  428.             addproc(pp);
  429.             n--;
  430.             cnt++;
  431.         }
  432.     }
  433. #ifdef    SUSPEND_PROC
  434.     for(pp = Susptab;n != 0 && pp != NULLPROC;pp = pnext){
  435.         pnext = pp->next;
  436.         if(pp->event == event){
  437. #ifdef    PROCTRACE
  438.             if(i_state){
  439.                 printf("psignal(%lx,%u) wake %lx [%s]\n",ptol(event),n,
  440.                  ptol(pp),pp->name);
  441.                 fflush(stdout);
  442.             }
  443. #endif /* PROCTRACE */
  444.             delproc(pp);
  445.             pp->state &= ~WAITING;
  446.             pp->event = 0;
  447.             pp->retval = 0;
  448.             addproc(pp);
  449.             n--;
  450.             cnt++;
  451.         }
  452.     }
  453. #endif    /* SUSPEND_PROC */
  454.     restore(i_state);
  455.     return cnt;
  456. }
  457.  
  458. /* Rename a process */
  459. void
  460. chname(pp,newname)
  461. struct proc *pp;
  462. char *newname;
  463. {
  464.     free(pp->name);
  465.     pp->name = strdup(newname);
  466. }
  467. /* Remove a process entry from the appropriate table */
  468. static void
  469. delproc(entry)
  470. register struct proc *entry;    /* Pointer to entry */
  471. {
  472.     int i_state;
  473.  
  474.     if(entry == NULLPROC)
  475.         return;
  476.  
  477.     i_state = dirps();
  478.     if(entry->next != NULLPROC)
  479.         entry->next->prev = entry->prev;
  480.     if(entry->prev != NULLPROC){
  481.         entry->prev->next = entry->next;
  482.     } else {
  483.         switch(entry->state){
  484.         case READY:
  485.             Rdytab = entry->next;
  486.             break;
  487.         case WAITING:
  488.             Waittab[phash(entry->event)] = entry->next;
  489.             break;
  490. #ifdef    SUSPEND_PROC
  491.         case SUSPEND:
  492.         case SUSPEND|WAITING:
  493.             Susptab = entry->next;
  494.             break;
  495. #endif
  496.         }
  497.     }
  498.     restore(i_state);
  499. }
  500. /* Append proc entry to end of appropriate list */
  501. static void
  502. addproc(entry)
  503. register struct proc *entry;    /* Pointer to entry */
  504. {
  505.     register struct proc *pp;
  506.     struct proc **head;
  507.     int i_state;
  508.  
  509.     if(entry == NULLPROC)
  510.         return;
  511.  
  512.     switch(entry->state){
  513.     case READY:
  514.         head = &Rdytab;
  515.         break;
  516.     case WAITING:
  517.         head = &Waittab[phash(entry->event)];
  518.         break;
  519. #ifdef    SUSPEND_PROC
  520.     case SUSPEND:
  521.     case SUSPEND|WAITING:
  522.         head = &Susptab;
  523.         break;
  524. #endif
  525.     }
  526.     entry->next = NULLPROC;
  527.     i_state = dirps();
  528.     if(*head == NULLPROC){
  529.         /* Empty list, stick at beginning */
  530.         entry->prev = NULLPROC;
  531.         *head = entry;
  532.     } else {
  533.         /* Find last entry on list */
  534.         for(pp = *head;pp->next != NULLPROC;pp = pp->next)
  535.             ;
  536.         pp->next = entry;
  537.         entry->prev = pp;
  538.     }
  539.     restore(i_state);
  540. }
  541.  
  542. #ifdef ATARI
  543. static unsigned  phash(void *event)
  544. {
  545.     char *cp     = (char *)&event;
  546.     int i         = sizeof(event);
  547.     unsigned x     = 0;
  548.  
  549.     while(i-- != 0)
  550.         x ^= *cp++;
  551.  
  552.     return x % PHASH;
  553. }
  554. #endif
  555.  
  556.